#include "include.h"
#include "func.h"
#include "func_aux.h"

#if FUNC_AUX_EN
func_aux_t f_aux;
void pcm_mono_drc_process(s16 *data);
#if AUX_REC_EN
AT(.text.bsp.aux)
void aux_rec_start(void)
{
    f_aux.rec_en = 1;
    karaok_aux_rec_enable();
}

AT(.text.bsp.aux)
void aux_rec_stop(void)
{
    f_aux.rec_en = 0;
    karaok_aux_rec_disable();
}

AT(.text.bsp.aux)
void aux_rec_init(void)
{
    rec_src.spr = SPR_44100;
    rec_src.source_start = aux_rec_start;
    rec_src.source_stop  = aux_rec_stop;
    f_aux.rec_en = 0;
    #if KARAOK_REC_EN && AUX_REC_EN
    if (xcfg_cb.auxr_sel && xcfg_cb.auxl_sel) {
        rec_src.nchannel = 0x12;
    } else {
        rec_src.nchannel = 0x11;
    }
    #else
    if (xcfg_cb.auxr_sel && xcfg_cb.auxl_sel) {
        rec_src.nchannel = 0x22;
    } else {
        rec_src.nchannel = 0x21;
    }
    #endif // KARAOK_REC_EN
}
#endif // AUX_REC_EN

//AT(.com_text)
//void pcm_manual_amplify(void *pcm_buf,u32 len, u16 gain)  //2^13  0DB
//{
//    s32 tem;
//    s16 *buf = (s16*)pcm_buf;
//    for(u32 i=0; i<len/2; i++){
//        tem = (buf[i]* gain)>>13;   //2^13 8192
//         if(tem < -32768){
//            tem = -32768;
//       }else if(tem > 32767){
//            tem = 32767;
//       }
//       buf[i] = tem;
//    }
//}
//
//AT(.com_text)
//void pcm_lr_exchange(void *pcm_buf,u32 len)  //PCM数据左右声道调换
//{
//    s16 *buf = (s16*)pcm_buf;
//    for(u32 i=0; i<len/2; i+=2){
//        s16 tmp = buf[i+1];
//        buf[i+1] = buf[i];
//        buf[i] = tmp;
//    }
//}

#if 0   //双声道AUX输入,DACL/DACR输出不同声音示例
//DACR: AUXL + AUXR
//DACL: AUXL
AT(.com_text.func.aux)
void aux_mix1_example(void *pcm_buf,u32 len)
{
    s16 *buf = (s16*)pcm_buf;
    for(u32 i=0; i<len/2; i+=2){
        buf[i+1] =  buf[i]/2 + buf[i+1]/2;   //DACR: AUXL + AUXR
    }
}

//DACR: AUXR
//DACL: 0
AT(.com_text.func.aux)
void aux_mix2_example(void *pcm_buf,u32 len)
{
    s16 *buf = (s16*)pcm_buf;
    for(u32 i=0; i<len/2; i+=2){
        buf[i] = 0;
    }
}


//DACR: AUXR+AUXL
//DACL: AUXR+AUXL
AT(.com_text.func.aux)
void aux_mix3_example(void *pcm_buf,u32 len)
{
    s16 *buf = (s16*)pcm_buf;
    for(u32 i=0; i<len/2; i+=2){
        buf[i] = buf[i]/2 + buf[i+1]/2;
        buf[i+1] = buf[i];
    }
}

//DACR: AUXR
//DACL: AUXR
AT(.com_text.func.aux)
void aux_mix4_example(void *pcm_buf,u32 len)
{
    s16 *buf = (s16*)pcm_buf;
    for(u32 i=0; i<len/2; i+=2){
        buf[i] = buf[i+1];
    }
}


//DACR: AUXR
//DACL: 音量可调,调节gain值即可
AT(.com_text.func.aux)
void aux_mix5_example(void *pcm_buf,u32 len)
{
    s16 *buf = (s16*)pcm_buf;
    s16 gain = GAIN_DIG_N25DB;
    for(u32 i=0; i<len/2; i+=2){
        s32 tem = buf[i];
        tem = (buf[i]* gain)>>13;   //0DB:2^13 8192
        if(tem < -32767){
            tem = -32767;
        }else if(tem > 32767){
            tem = 32767;
        }
        buf[i] = tem;
    }
}
#endif

//#if PCM_DRC_EN  //DRC只限左声道示例
//AT(.com_text.func.aux)
//void aux_left_drc_process(void *pcm_buf,u32 len)  //AUX 左声道开启DRC，右声道保持不变
//{
//    s16 *buf = (s16*)pcm_buf;
//    for(u32 i=0; i<len/2; i+=2){
//        pcm_mono_drc_process(&buf[i]);
//    }
//}
//#endif


//void aux_rm_voice_porcess(u8 *ptr, u32 samples, int ch_mode)
//{
//    s16 *ldata = (s16*)ptr;
//    s16 *rdata = ldata + 1;
//    if (ch_mode) {  //双声道
//        for (int i = 0; i < samples; i++) {
//            dac_sw_rm_voice(ldata,rdata);
//            ldata += 2;
//            rdata += 2;
//        }
//    } else {  //单声道
//        for (int i = 0; i < samples; i++) {
//            dac_sw_rm_voice(ldata,ldata);
//            ldata += 1;
//        }
//    }
//}


AT(.com_text.func.aux)
void aux_sdadc_process(u8 *ptr, u32 samples, int ch_mode)
{

//    if (ext_rm_voice_en) {
//        aux_rm_voice_porcess(ptr,samples,ch_mode);
//    }

#if AUX_REC_EN
    if (f_aux.rec_en) {
#if KARAOK_REC_EN
        if (!karaok_rec_fill_buf(ptr))
#endif
        {
            puts_rec_obuf(ptr, (u16)(samples << (1 + ch_mode)));
        }
    }
#endif // AUX_REC_EN

#if AUX_DNR_EN
    aux_dnr_detect(ptr,128);
#endif

//#if PCM_DRC_EN
//    aux_left_drc_process(ptr,(samples*2)<<ch_mode);
//#endif


//    aux_mix5_example(ptr,(samples*2)<<ch_mode);
//    pcm_manual_amplify(ptr,(samples*2)<<ch_mode,GAIN_DIG_P7DB); //AUX数字放大示例 //ch_mode 0 单声道, 1双声道
//    if (ch_mode) {  //AUX双声道左右声道调换示例
//        pcm_lr_exchange(ptr, samples*4);
//    }
    sdadc_pcm_2_dac(ptr, samples, ch_mode);
}

AT(.text.bsp.aux)
void func_aux_mp3_res_play(u32 addr, u32 len)
{
    if (len == 0) {
        return;
    }

#if AUX_REC_EN
    sfunc_record_pause();
#endif // AUX_REC_EN

    if (!f_aux.pause) {
        func_aux_stop();
        mp3_res_play(addr, len);
        func_aux_start();
    } else {
        mp3_res_play(addr, len);
    }

#if AUX_REC_EN
    sfunc_record_continue();
#endif // AUX_REC_EN
}

AT(.text.func.aux)
void func_aux_start(void)
{
    bsp_aux_start(get_aux_channel_cfg(), xcfg_cb.aux_anl_gain, f_aux.aux2adc);
}

AT(.text.func.aux)
void func_aux_stop(void)
{
    bsp_aux_stop(get_aux_channel_cfg(), f_aux.aux2adc);
}

AT(.text.func.aux)
void func_aux_pause_play(void)
{
    if (f_aux.pause) {
        led_aux_play();
        func_aux_start();
    } else {
        led_idle();
        func_aux_stop();
    }
    f_aux.pause ^= 1;
#if BT_APP_EN
    bsp_app_msc_play_sta(f_aux.pause ? 1 : 2, 0);
#endif
}

AT(.text.func.aux)
void func_aux_setvol_callback(u8 dir)
{
    if (f_aux.pause) {
        func_aux_pause_play();
    }
}

AT(.text.func.aux)
void func_aux_process(void)
{
    func_process();
#if AUX_DNR_EN
    aux_dnr_process();
#endif
}

#if MICAUX_ANALOG_OUT_ALWAYS
void micaux_analog_out_init(void)
{
    printf("micaux_analog_out_init...\n");
    if (FUNC_AUX != func_cb.sta){
        analog_aux2pa_start(CH_AUXL_MICR, 0);
        set_aux_analog_gain(xcfg_cb.aux_anl_gain, CH_AUXL_MICR);          //set aux analog gain
        analog_aux2pa_dig2anl_enable(0);
    }
    //可以独立关闭一些不需要的通道，关后需要调用aux_analog_channel_select才有声音出来
    //aux_analog_channel_close(CH_AUXL_PF0);
    //aux_analog_channel_close(CH_AUXR_PF1);
    aux_analog_channel_select(MICAUX_ANALOG_OUT_CH);
    dac_fade_in();
}
#endif

#if PCM_DRC_EN
void drc_mono_process(s32 *data);
bool soft_eq_drc_check_crc(u8 type, u8 *buf);
bool drc_init(u8 type, const u32 *coef);



AT(.com_text.pcm_drc)
void pcm_mono_drc_process(s16 *data)
{
    s32 value = *data;
    drc_mono_process(&value);
	*data = (s16)value;
}

void pcm_drc_res_init(void *res)
{
    if (!soft_eq_drc_check_crc(1,res)) {
        printf("pcm.res file crc err\n");
        return;
    }
    if (!drc_init(1, (u32*)res+2)) {
        printf("drc_init err\n");
        return;
    }
    printf("pcm_drc_res_init ok\n");
}
#endif

#if MIC_DETECT_CONTROL_CHANNEL && FUNC_AUX_EN
void karaok_mic_detect_aux_gain_adjust(void)    // MIC插入时缩小AUX音量，防止混合时失真（AUX混合是直接左右相加给ADC采集）
{
    if(dev_is_online(DEV_MIC)) {
        u8 aux_gain = xcfg_cb.aux_anl_gain >= 2 ? xcfg_cb.aux_anl_gain - 2 : 0;
        set_aux_analog_gain(aux_gain,MIC_DETECT_CONTROL_CHANNEL_R);
        set_aux_analog_gain(aux_gain,MIC_DETECT_CONTROL_CHANNEL_L);
    } else {
        set_aux_analog_gain(xcfg_cb.aux_anl_gain,MIC_DETECT_CONTROL_CHANNEL_R);
        set_aux_analog_gain(xcfg_cb.aux_anl_gain,MIC_DETECT_CONTROL_CHANNEL_L);
    }
}
#endif // MIC_DETECT_CONTROL_CHANNEL && FUNC_AUX_EN

void func_aux_enter(void)
{
    if (!is_linein_enter_enable()) {
        func_cb.sta = FUNC_NULL;
        return;
    }

    memset(&f_aux, 0, sizeof(func_aux_t));
    f_aux.aux2adc = ((u8)(AUX_2_SDADC_EN & xcfg_cb.aux_2_sdadc_en) << 7) | AUDIO_PATH_AUX;
    func_cb.mp3_res_play = func_aux_mp3_res_play;
    func_cb.set_vol_callback = func_aux_setvol_callback;
    msg_queue_clear();

#if AUX_DNR_EN
    aux_dnr_init(10, 1000, 20, 1500);
#endif

//#if PCM_DRC_EN
//    pcm_drc_res_init((u8*)RES_BUF_DRC_PCM_DRC);
//#endif


#if AUX_REC_EN
    aux_rec_init();
#endif // AUX_REC_EN

    led_aux_play();
    func_aux_enter_display();
#if WARNING_FUNC_AUX
    mp3_res_play(RES_BUF_AUX_MODE_MP3, RES_LEN_AUX_MODE_MP3);
#endif // WARNING_FUNC_AUX

#if BT_APP_EN
    bsp_app_func_send(func_cb.sta);
#endif

#if SYS_KARAOK_EN
    dac_fade_out();
    bsp_karaok_exit(AUDIO_PATH_KARAOK);
#endif
#if MICAUX_ANALOG_OUT_ALWAYS
    analog_aux2pa_exit(MICAUX_ANALOG_OUT_CH);
#endif
    func_aux_start();

#if AUXR_MIX_AUXL2ADC
    void aux_analog_channel_select(u8 channel);
    aux_analog_channel_select(AUXR_MIX_AUXLCHANENL);
    aux_shorting_enable();
//    aux_shorting_disable();
//    void aux_analog_channel_close(u8 channel);
//    aux_analog_channel_close(AUXR_MIX_AUXLCHANENL);
#endif // AUXR_MIX_AUXL2ADC

#if SYS_KARAOK_EN
#if MIC_DETECT_CONTROL_CHANNEL && FUNC_AUX_EN
    if((dev_is_online(DEV_MIC)) && (FUNC_AUX == func_cb.sta)) {
        func_aux_stop();
        if(MIC_DETECT_CONTROL_CHANNEL_MIX >> 4){
            xcfg_cb.auxl_sel = MIC_DETECT_CONTROL_CHANNEL_L;
            xcfg_cb.auxr_sel = 0;
        } else {
            xcfg_cb.auxr_sel = MIC_DETECT_CONTROL_CHANNEL_L;
            xcfg_cb.auxl_sel = 0;
        }
    func_aux_start();
    void aux_analog_channel_select(u8 channel);
    aux_analog_channel_select(MIC_DETECT_CONTROL_CHANNEL_MIX);
    aux_shorting_enable();
    bsp_karaok_init(AUDIO_PATH_KARAOK, FUNC_AUX);
    #if AUX_REC_EN
    aux_rec_init();
    #endif
    }
    else{
        bsp_karaok_init(AUDIO_PATH_KARAOK, FUNC_AUX);
    }
    karaok_mic_detect_aux_gain_adjust();
#else
    bsp_karaok_init(AUDIO_PATH_KARAOK, FUNC_AUX);
#endif // MIC_DETECT_CONTROL_CHANNEL
#endif // SYS_KARAOK_EN

#if MICAUX_ANALOG_OUT_ALWAYS
    micaux_analog_out_init();
#endif
}


void func_aux_exit(void)
{
#if AUX_REC_EN
    sfunc_record_stop();
#endif // AUX_REC_EN

    func_aux_exit_display();
    func_aux_stop();
    func_cb.last = FUNC_AUX;
}

AT(.text.func.aux)
void func_aux(void)
{
    printf("%s\n", __func__);

    func_aux_enter();

    while (func_cb.sta == FUNC_AUX) {
        func_aux_process();
        func_aux_message(msg_dequeue());
        func_aux_display();
    }

    func_aux_exit();
}
#endif  //FUNC_AUX_EN
